package com.girant.logger.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.girant.dict.api.DictApi;
import com.girant.dict.entity.dto.SysDictItemDTO;
import com.girant.logger.config.BoostConfig;
import com.girant.logger.entity.domain.ErrorLogDocumentDO;
import com.girant.logger.entity.domain.LogDocumentDO;
import com.girant.logger.entity.dto.ErrorLogDTO;
import com.girant.logger.entity.dto.ErrorLogExportDTO;
import com.girant.logger.entity.vo.show.ErrorLogVO;
import com.girant.logger.mapper.ErrorLogMapper;
import com.girant.logger.service.ErrorLogService;
import com.girant.logger.utils.SearchUtil;
import com.girant.mybatis.entity.BasePage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.easyes.core.biz.EsPageInfo;
import org.dromara.easyes.core.conditions.select.LambdaEsQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.girant.logger.config.Constants.DICT_CODE_SERVER;

@Slf4j
@Service
@RequiredArgsConstructor
public class ErrorLogServiceImpl implements ErrorLogService {
    @Autowired
    private ErrorLogMapper ErrorLogMapper;
    @Autowired
    private DictApi dictApi;

    @Autowired
    private BoostConfig boostConfig;

    @Value("${es.min.score:0.2}")
    private Double minScore;

    @Override
    public BasePage<ErrorLogVO> queryErrorLogPage(ErrorLogDTO request) {
        long from = (request.getPageNum() - 1) * request.getPageSize();
        long size = request.getPageSize();

        // 1. 构建查询条件并打印
        LambdaEsQueryWrapper<ErrorLogDocumentDO> wrapper = buildBoolQuery(request);
        wrapper.orderByDesc(ErrorLogDocumentDO::getOperationTime);

        if (StrUtil.isNotBlank(request.getKeyword())){
            wrapper.minScore(minScore);
        }


        //2.分页取出指定页数
        EsPageInfo<ErrorLogDocumentDO> esPageInfo = ErrorLogMapper.pageQuery(wrapper, (int) from, (int) size);

        // 3. 处理查询结果
        long total = esPageInfo.getTotal();
        List<ErrorLogDocumentDO> documents = esPageInfo.getList();
        // 4. 创建分页参数（3.0.0版本语法）
        log.info("执行ES查询：分页参数[pageNum={}, pageSize={}]", from, size);


        //4.获得字典映射
        List<SysDictItemDTO> list = dictApi.getDictList(DICT_CODE_SERVER);
        Map<String, String> map = list.stream().collect(Collectors.toMap(SysDictItemDTO::getDictKey, SysDictItemDTO::getDictLabel));

        //5. 转换为VO
        List<ErrorLogVO> records = documents.stream()
                .map(document -> {
                    // 创建VO对象
                    ErrorLogVO vo = BeanUtil.copyProperties(document, ErrorLogVO.class);
                    // 设置serverNameLabel的字典值
                    vo.setServerNameLabel(
                            map.getOrDefault(document.getServerName(), ""));
                    return vo;
                })
                .collect(Collectors.toList());


        //6.获得总页数
        long totalPages = esPageInfo.getPages();
        log.info("ES查询总命中数：{}条, 当前页数据量：{}条,分页数量{}页", total, documents.size(), totalPages);
        return new BasePage<>(
                records,
                request.getPageNum(),
                request.getPageSize(),
                total,
                totalPages
        );

    }

    private LambdaEsQueryWrapper<ErrorLogDocumentDO> buildBoolQuery(ErrorLogDTO request) {
        LambdaEsQueryWrapper<ErrorLogDocumentDO> wrapper = new LambdaEsQueryWrapper<>();
        // 1. 时间范围过滤
        if (ObjectUtil.isNotEmpty(request.getOperationStartTime())) {
            wrapper.ge(ErrorLogDocumentDO::getOperationTime, DateUtil.format(request.getOperationStartTime(), DatePattern.NORM_DATETIME_MS_PATTERN));//大于等于，并且转化格式
        }
        // 处理结束时间
        if (ObjectUtil.isNotEmpty(request.getOperationEndTime())) {
            wrapper.le(ErrorLogDocumentDO::getOperationTime, DateUtil.format(request.getOperationEndTime(), DatePattern.NORM_DATETIME_MS_PATTERN));//小于等于，并且转化格式
        }
        // 2. IP模糊匹配（CIDR格式）
        if (StrUtil.isNotBlank(request.getSourceIp())) {
            String cidr = SearchUtil.convertIpPrefixToCidr(request.getSourceIp());
            wrapper.eq(ErrorLogDocumentDO::getSourceIp, cidr);
        }
        // 3. LogLevel精确排除杂余数据
        wrapper.eq(ErrorLogDocumentDO::getLogLevel, "ERROR");

        // 4. traceId/spanId 精确匹配
        if (StrUtil.isNotBlank(request.getTraceId())) {
            wrapper.eq(ErrorLogDocumentDO::getTraceId, request.getTraceId());
        }
        if (StrUtil.isNotBlank(request.getSpanId())) {
            wrapper.eq(ErrorLogDocumentDO::getSpanId, request.getSpanId());
        }
        //5.精确匹配ServerName
        if (StrUtil.isNotBlank(request.getServerName())) {
            wrapper.eq(ErrorLogDocumentDO::getServerName, request.getServerName());
        }


         //6.关键字多字段匹配
        if (StrUtil.isNotBlank(request.getKeyword())) {
            wrapper.should(w -> w.match(ErrorLogDocumentDO::getErrorInfo, request.getKeyword(), boostConfig.getErrorInfo()));
                    wrapper.should(w -> w.match(ErrorLogDocumentDO::getStackTrace, request.getKeyword(), boostConfig.getStackTrace()));
                    wrapper.should(w -> w.eq(ErrorLogDocumentDO::getClientBrowser, request.getKeyword(), boostConfig.getClientBrowser()));
                    wrapper.should(w -> w.eq(ErrorLogDocumentDO::getClientVersion, request.getKeyword(), boostConfig.getClientVersion()));
                    wrapper.should(w -> w.eq(ErrorLogDocumentDO::getOperationNickname, request.getKeyword()));
        }
        return wrapper;
    }


}